package org.therandoms.textgen;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wordnik.client.api.WordsApi;
import com.wordnik.client.model.WordObject;

/**
 * Contains methods for working with the Wordnik API
 * 
 * @author Logan Widick
 * @author Vinh Pham
 */
public class WordnikPuller {

	/**
	 * The instance of the Wordnik API class for grabbing lists of random words.
	 */
	private static WordsApi wordApi = new WordsApi();

	/**
	 * The site to check for bad words
	 */
	private static final String BAD_WORD_SITE = "http://www.wdyl.com/profanity?q=";

	/**
	 * Converts a collection into a comma-separated string.
	 * 
	 * @param collection
	 *            the collection
	 * @return a new comma separated string
	 */
	public static <T> String collToString(List<T> collection) {
		StringBuilder result = new StringBuilder();
		for (T mT : collection) {
			result.append(mT.toString());
			result.append(",");
		}
		return result.length() > 0 ? result.substring(0, result.length() - 1)
				: "";
	}

	/**
	 * A simple static class for parsing JSON responses from
	 * http://www.wdyl.com/profanity.
	 * 
	 * @author logan
	 *
	 */
	public static class BadWordResponse {

		/**
		 * Dummy constructor
		 */
		public BadWordResponse() {

		}

		/**
		 * Constructor
		 * 
		 * @param response
		 *            whether or not the word is bad
		 */
		public BadWordResponse(boolean response) {
			this.response = response;
		}

		/**
		 * Returns whether or not the word is bad
		 * 
		 * @return true if bad; otherwise false
		 */
		public boolean isResponse() {
			return response;
		}

		/**
		 * Sets whether the word is bad
		 * 
		 * @param response
		 *            true if bad; otherwise false
		 */
		public void setResponse(boolean response) {
			this.response = response;
		}

		/**
		 * Stores whether or not the word is bad.
		 */
		private boolean response;

	}

	/**
	 * A function to check if a word is a bad word.
	 * 
	 * @param word
	 *            The word to check
	 * @return true if bad; otherwise false.
	 */
	public static boolean isBadWord(String word) {
		boolean retVal = false;
		try {
			ObjectMapper mapper = new ObjectMapper();

			
			JsonFactory factory = new JsonFactory();
			
			URL testURL = new URL("derp");
			HttpURLConnection mConn = (HttpURLConnection) testURL.openConnection();
			JsonGenerator testGenerator = factory.createGenerator(mConn.getOutputStream());
			mapper.writeValue(testGenerator, new BadWordResponse());
			testGenerator.flush();
			
			JsonParser parser = factory.createParser(new URL(BAD_WORD_SITE
					+ URLEncoder.encode(word, "utf-8")));

			BadWordResponse resp = mapper.readValue(parser,
					BadWordResponse.class);
			retVal = resp.isResponse();
			parser.close();

		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return retVal;
	}

	/**
	 * Uses the Wordnik API to add results to a production category
	 * 
	 * @param opts
	 *            the wordnik options
	 * 
	 * @return the words added
	 */
	public static List<WordObject> addRandomWordnikResults(WordnikOptions opts) {
		List<WordObject> retList = new ArrayList<WordObject>();
		try {
			wordApi.getInvoker().addDefaultHeader("api_key", opts.wordnikAPIKey);

			/*
			 * Arguments: (String includePartOfSpeech, String
			 * excludePartOfSpeech, String sortBy, String sortOrder, String
			 * hasDictionaryDef, Integer minCorpusCount, Integer maxCorpusCount,
			 * Integer minDictionaryCount, Integer maxDictionaryCount, Integer
			 * minLength, Integer maxLength, Integer limit) throws ApiException
			 * {
			 */
			List<WordObject> randomWords = wordApi.getRandomWords(
					collToString(opts.wordnikCategoriesToInclude),
					collToString(opts.wordnikCategoriesToExclude),
					opts.sortBy.toString(), opts.sortOrder.toString(),
					String.valueOf(opts.hasDictionaryDef), opts.minCorpusCount,
					opts.maxCorpusCount, opts.minDictionaryCount,
					opts.maxDictionaryCount, opts.minWordLength,
					opts.maxWordLength, opts.numResultsDesired);
			
			for (WordObject wo : randomWords) {
				boolean vulg = false;
				if (opts.enableBadWordsFiltering) {
					vulg = isBadWord(wo.getWord());
				}

				if (!vulg) {
					Production<String> mProduction = new Production<String>();
					mProduction.addSymbolToProduction(wo.getWord());
					opts.dictionaryToLoad.addProductionToCategory(mProduction,
							opts.grammarCategoryToLoad);
					retList.add(wo);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return retList;
	}

}
